package services

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	"domain-system/config"
)

// OpenIMService OpenIM服务
type OpenIMService struct {
	config        *config.Config
	isInitialized bool
	mutex         sync.RWMutex
}

// NewOpenIMService 创建OpenIM服务
func NewOpenIMService(cfg *config.Config) *OpenIMService {
	return &OpenIMService{
		config: cfg,
	}
}

// RegisterUserRequest 注册用户请求结构
type RegisterUserRequest struct {
	DeviceID       string                 `json:"deviceID"`
	VerifyCode     string                 `json:"verifyCode"`
	Platform       int                    `json:"platform"`
	InvitationCode string                 `json:"invitationCode,omitempty"`
	AutoLogin      bool                   `json:"autoLogin"`
	User           map[string]interface{} `json:"user"`
}

// LoginCertificate 登录凭证
type LoginCertificate struct {
	UserID    string `json:"userID"`
	Token     string `json:"token"`
	IMToken   string `json:"imToken"`
	ChatToken string `json:"chatToken"`
}

// OpenIMRegisterResponse OpenIM注册API响应
type OpenIMRegisterResponse struct {
	ErrCode int    `json:"errCode"`
	ErrMsg  string `json:"errMsg"`
	ErrDlt  string `json:"errDlt"`
	Data    struct {
		UserID    string `json:"userID"`
		Token     string `json:"token"`
		IMToken   string `json:"imToken"`
		ChatToken string `json:"chatToken"`
	} `json:"data"`
}

// AdminDeleteUserRequest 管理员删除用户请求结构
type AdminDeleteUserRequest struct {
	Secret      string   `json:"secret"`
	UserIDList  []string `json:"userIDList"`
	OperationID string   `json:"operationID"`
}

// AdminDeleteUserResponse 管理员删除用户响应结构
type AdminDeleteUserResponse struct {
	ErrCode int    `json:"errCode"`
	ErrMsg  string `json:"errMsg"`
	ErrDlt  string `json:"errDlt"`
	Data    struct {
		Success []string `json:"success"`
		Failed  []string `json:"failed"`
	} `json:"data"`
}

// generateMD5 生成MD5哈希
func generateMD5(text string) string {
	hash := md5.Sum([]byte(text))
	return hex.EncodeToString(hash[:])
}

// RegisterUser 注册用户 - 基于Android客户端实现
func (s *OpenIMService) RegisterUser(nickname, password, phone, email string, areaCode ...string) (*LoginCertificate, error) {
	// 构建注册请求URL
	url := fmt.Sprintf("%s/account/register", s.config.OpenIMAPIURL)

	// 设置默认区号
	defaultAreaCode := "+86" // 中国区号作为默认值
	if len(areaCode) > 0 && areaCode[0] != "" {
		defaultAreaCode = areaCode[0]
	}

	// 构建用户信息
	userInfo := map[string]interface{}{
		"nickname": nickname,
		"password": generateMD5(password), // MD5加密密码
	}

	// 添加可选字段
	if phone != "" {
		userInfo["phoneNumber"] = phone
		// 如果有手机号，自动添加区号
		userInfo["areaCode"] = defaultAreaCode
	}
	if email != "" {
		userInfo["email"] = email
	}

	// 构建请求体
	requestBody := RegisterUserRequest{
		DeviceID:   fmt.Sprintf("server_%d", time.Now().UnixNano()),
		VerifyCode: "666666", // 服务端注册可以使用默认验证码
		Platform:   2,        // 服务器平台ID
		AutoLogin:  true,
		User:       userInfo,
	}

	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	// 发送HTTP请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("operationID", fmt.Sprintf("register_%d", time.Now().UnixNano()))

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}

	log.Printf("注册API响应状态: %d", resp.StatusCode)
	log.Printf("注册API响应内容: %s", string(bodyBytes))

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("注册失败，状态码: %d，响应: %s", resp.StatusCode, string(bodyBytes))
	}

	// 解析响应
	var apiResp OpenIMRegisterResponse
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return nil, fmt.Errorf("解析注册响应失败: %v", err)
	}

	// 检查业务错误码
	if apiResp.ErrCode != 0 {
		return nil, fmt.Errorf("注册失败: %s (错误码: %d)", apiResp.ErrMsg, apiResp.ErrCode)
	}

	// 构建登录凭证
	result := &LoginCertificate{
		UserID:    apiResp.Data.UserID,
		Token:     apiResp.Data.Token,
		IMToken:   apiResp.Data.IMToken,
		ChatToken: apiResp.Data.ChatToken,
	}

	return result, nil
}

// OpenIMLoginRequest OpenIM登录请求结构 - 基于Android客户端实现
type OpenIMLoginRequest struct {
	AreaCode    string `json:"areaCode,omitempty"`
	Account     string `json:"account,omitempty"`
	PhoneNumber string `json:"phoneNumber,omitempty"`
	Email       string `json:"email,omitempty"`
	Password    string `json:"password"`
	Platform    int    `json:"platform"`
	VerifyCode  string `json:"verifyCode,omitempty"`
}

// OpenIMLoginResponse OpenIM登录API响应结构
type OpenIMLoginResponse struct {
	ErrCode int    `json:"errCode"`
	ErrMsg  string `json:"errMsg"`
	ErrDlt  string `json:"errDlt"`
	Data    struct {
		UserID      string `json:"userID"`
		AccessToken string `json:"accessToken"` // 登录API可能使用accessToken
		Token       string `json:"token"`       // 备用字段
		IMToken     string `json:"imToken"`
		ChatToken   string `json:"chatToken"`
		ExpiredTime int64  `json:"expiredTime,omitempty"` // 登录API可能包含过期时间
	} `json:"data"`
}

// LoginToOpenIM 登录到OpenIM获取token
func (s *OpenIMService) LoginToOpenIM(userID, password, areaCode string) (*LoginCertificate, error) {
	// 构建登录请求URL
	url := fmt.Sprintf("%s/account/login", s.config.OpenIMAPIURL)

	// 根据userID的格式判断是手机号还是邮箱
	var requestBody OpenIMLoginRequest
	if strings.Contains(userID, "@") {
		// 邮箱登录
		requestBody = OpenIMLoginRequest{
			Email:    userID,
			Password: generateMD5(password),
			Platform: 2, // 服务器平台ID
		}
	} else {
		// 手机号登录
		requestBody = OpenIMLoginRequest{
			AreaCode:    areaCode, // 默认中国区号
			PhoneNumber: userID,
			Password:    generateMD5(password),
			Platform:    2, // 服务器平台ID
		}
	}

	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	// 发送HTTP请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("operationID", fmt.Sprintf("login_%d", time.Now().UnixNano()))

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}

	log.Printf("登录API响应状态: %d", resp.StatusCode)
	log.Printf("登录API响应内容: %s", string(bodyBytes))

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("登录失败，状态码: %d，响应: %s", resp.StatusCode, string(bodyBytes))
	}

	// 解析响应 - 使用专门的登录响应结构
	var apiResp OpenIMLoginResponse
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return nil, fmt.Errorf("解析登录响应失败: %v", err)
	}

	// 检查业务错误码
	if apiResp.ErrCode != 0 {
		return nil, fmt.Errorf("登录失败: %s (错误码: %d)", apiResp.ErrMsg, apiResp.ErrCode)
	}

	// 构建登录凭证 - 优先使用accessToken，如果为空则使用token
	token := apiResp.Data.AccessToken
	if token == "" {
		token = apiResp.Data.Token
	}

	result := &LoginCertificate{
		UserID:    apiResp.Data.UserID,
		Token:     token,
		IMToken:   apiResp.Data.IMToken,
		ChatToken: apiResp.Data.ChatToken,
	}

	return result, nil
}

// LoginToOpenIMWithVerificationCode 使用验证码登录到OpenIM
func (s *OpenIMService) LoginToOpenIMWithVerificationCode(userID, verificationCode string, areaCode ...string) (*LoginCertificate, error) {
	// 构建登录请求URL
	url := fmt.Sprintf("%s/account/login", s.config.OpenIMAPIURL)

	// 设置默认区号
	defaultAreaCode := "+86" // 中国区号作为默认值
	if len(areaCode) > 0 && areaCode[0] != "" {
		defaultAreaCode = areaCode[0]
	}

	// 设置默认验证码
	defaultVerifyCode := "666666" // 默认验证码
	if verificationCode != "" {
		defaultVerifyCode = verificationCode
	}

	// 根据userID的格式判断是手机号还是邮箱
	var requestBody OpenIMLoginRequest
	if strings.Contains(userID, "@") {
		// 邮箱登录
		requestBody = OpenIMLoginRequest{
			Email:      userID,
			VerifyCode: defaultVerifyCode,
			Platform:   2, // 服务器平台ID
		}
	} else {
		// 手机号登录
		requestBody = OpenIMLoginRequest{
			AreaCode:    defaultAreaCode,
			PhoneNumber: userID,
			VerifyCode:  defaultVerifyCode,
			Platform:    2, // 服务器平台ID
		}
	}

	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	// 发送HTTP请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("operationID", fmt.Sprintf("verify_login_%d", time.Now().UnixNano()))

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}

	log.Printf("验证码登录API响应状态: %d", resp.StatusCode)
	log.Printf("验证码登录API响应内容: %s", string(bodyBytes))

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("验证码登录失败，状态码: %d，响应: %s", resp.StatusCode, string(bodyBytes))
	}

	// 解析响应
	var apiResp OpenIMLoginResponse
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return nil, fmt.Errorf("解析验证码登录响应失败: %v", err)
	}

	// 检查业务错误码
	if apiResp.ErrCode != 0 {
		return nil, fmt.Errorf("验证码登录失败: %s (错误码: %d)", apiResp.ErrMsg, apiResp.ErrCode)
	}

	// 构建登录凭证
	token := apiResp.Data.AccessToken
	if token == "" {
		token = apiResp.Data.Token
	}

	result := &LoginCertificate{
		UserID:    apiResp.Data.UserID,
		Token:     token,
		IMToken:   apiResp.Data.IMToken,
		ChatToken: apiResp.Data.ChatToken,
	}

	return result, nil
}

// LoginToOpenIMWithDefaultVerificationCode 使用默认验证码登录到OpenIM（便捷方法）
func (s *OpenIMService) LoginToOpenIMWithDefaultVerificationCode(userID string, areaCode ...string) (*LoginCertificate, error) {
	return s.LoginToOpenIMWithVerificationCode(userID, "666666", areaCode...)
}

// AdminTokenRequest 管理员token请求结构 - 根据官方SDK更新
type AdminTokenRequest struct {
	UserID string `json:"userID"`
	Secret string `json:"secret"`
}

// AdminTokenResponse 管理员token响应结构 - 根据官方SDK更新
type AdminTokenResponse struct {
	ErrCode int    `json:"errCode"`
	ErrMsg  string `json:"errMsg"`
	Data    struct {
		Token       string `json:"token"`
		UserID      string `json:"userID"`
		ExpiredTime int64  `json:"expiredTime"`
	} `json:"data"`
}

func (s *OpenIMService) GetAdminToken() (string, error) {
	// 使用官方的管理员token获取接口
	url := fmt.Sprintf("%s/auth/get_admin_token", s.config.OpenIMAdminURL)
	log.Printf("管理员token API URL: %s", url)

	// 构建请求体 - 使用官方SDK的格式
	requestBody := AdminTokenRequest{
		UserID: s.config.OpenIMAdminUser,
		Secret: s.config.OpenIMSecret,
	}
	log.Printf("管理员token请求数据: UserID=%s, Secret=%s", requestBody.UserID, requestBody.Secret)
	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return "", fmt.Errorf("序列化管理员token请求数据失败: %v", err)
	}

	// 发送HTTP请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return "", fmt.Errorf("创建管理员token HTTP请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("operationID", fmt.Sprintf("admin_token_%d", time.Now().UnixNano()))
	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("发送管理员token HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取管理员token响应内容失败: %v", err)
	}

	log.Printf("管理员token API响应状态: %d", resp.StatusCode)
	log.Printf("管理员token API响应内容: %s", string(bodyBytes))

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("获取管理员token失败，状态码: %d，响应: %s", resp.StatusCode, string(bodyBytes))
	}

	// 解析响应
	var apiResp AdminTokenResponse
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return "", fmt.Errorf("解析管理员token响应失败: %v", err)
	}

	// 检查业务错误码
	if apiResp.ErrCode != 0 {
		return "", fmt.Errorf("获取管理员token失败: %s (错误码: %d)", apiResp.ErrMsg, apiResp.ErrCode)
	}

	// 返回token
	if apiResp.Data.Token == "" {
		return "", fmt.Errorf("管理员token响应中未找到有效的token")
	}

	return apiResp.Data.Token, nil
}

// LoginToOpenIMWithPlatform 登录到OpenIM获取token（支持传入平台类型）
func (s *OpenIMService) LoginToOpenIMWithPlatform(userID, password, areaCode string, platform int) (*LoginCertificate, error) {
	if platform == 0 {
		platform = 2
	}
	url := fmt.Sprintf("%s/account/login", s.config.OpenIMAPIURL)

	var requestBody OpenIMLoginRequest
	if strings.Contains(userID, "@") {
		requestBody = OpenIMLoginRequest{
			Email:    userID,
			Password: generateMD5(password),
			Platform: platform,
		}
	} else {
		requestBody = OpenIMLoginRequest{
			AreaCode:    areaCode,
			PhoneNumber: userID,
			Password:    generateMD5(password),
			Platform:    platform,
		}
	}

	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("operationID", fmt.Sprintf("login_%d", time.Now().UnixNano()))

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}

	log.Printf("登录API响应状态: %d", resp.StatusCode)
	log.Printf("登录API响应内容: %s", string(bodyBytes))

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("登录失败，状态码: %d，响应: %s", resp.StatusCode, string(bodyBytes))
	}

	var apiResp OpenIMLoginResponse
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return nil, fmt.Errorf("解析登录响应失败: %v", err)
	}
	if apiResp.ErrCode != 0 {
		return nil, fmt.Errorf("登录失败: %s (错误码: %d)", apiResp.ErrMsg, apiResp.ErrCode)
	}

	result := &LoginCertificate{
		UserID:    apiResp.Data.UserID,
		Token:     apiResp.Data.Token,
		IMToken:   apiResp.Data.IMToken,
		ChatToken: apiResp.Data.ChatToken,
	}
	return result, nil
}

// LoginToOpenIMWithVerificationCodeWithPlatform 使用验证码登录到OpenIM（支持传入平台类型）
func (s *OpenIMService) LoginToOpenIMWithVerificationCodeWithPlatform(userID, verificationCode string, areaCode string, platform int) (*LoginCertificate, error) {
	if platform == 0 {
		platform = 2
	}
	url := fmt.Sprintf("%s/account/login", s.config.OpenIMAPIURL)

	var requestBody OpenIMLoginRequest
	if strings.Contains(userID, "@") {
		requestBody = OpenIMLoginRequest{
			Email:      userID,
			VerifyCode: verificationCode,
			Password:   "", // 验证码登录不传密码
			Platform:   platform,
		}
	} else {
		requestBody = OpenIMLoginRequest{
			AreaCode:    areaCode,
			PhoneNumber: userID,
			VerifyCode:  verificationCode,
			Password:    "", // 验证码登录不传密码
			Platform:    platform,
		}
	}

	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("operationID", fmt.Sprintf("verify_login_%d", time.Now().UnixNano()))

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}

	log.Printf("验证码登录API响应状态: %d", resp.StatusCode)
	log.Printf("验证码登录API响应内容: %s", string(bodyBytes))

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("验证码登录失败，状态码: %d，响应: %s", resp.StatusCode, string(bodyBytes))
	}

	var apiResp OpenIMLoginResponse
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return nil, fmt.Errorf("解析验证码登录响应失败: %v", err)
	}
	if apiResp.ErrCode != 0 {
		return nil, fmt.Errorf("验证码登录失败: %s (错误码: %d)", apiResp.ErrMsg, apiResp.ErrCode)
	}

	result := &LoginCertificate{
		UserID:    apiResp.Data.UserID,
		Token:     apiResp.Data.Token,
		IMToken:   apiResp.Data.IMToken,
		ChatToken: apiResp.Data.ChatToken,
	}
	return result, nil
}
